/*
 * Copyright 2012 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package io.netty.example.echo;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;

/**
 * Sends one message when a connection is open and echoes back any received
 * data to the server.
 * 当链接打开 , 发送一条消息给服务端, 服务端将消息全返回回来.
 * Simply put, the echo client initiates the ping-pong
 * traffic between the echo client and server by sending the first message to
 * the server.
 * 简单的推送 , 数据从客户端 发送到服务端后, 再返回
 */
public final class EchoClient {
    //是否SSL
    static final boolean SSL = System.getProperty("ssl") != null;
    //服务端HOST , 本地
    static final String HOST = System.getProperty("host", "127.0.0.1");
    //服务端端口 ,port: 8007
    static final int PORT = Integer.parseInt(System.getProperty("port", "8007"));
    //
    static final int SIZE = Integer.parseInt(System.getProperty("size", "256"));

    public static void main(String[] args) throws Exception {
        // Configure SSL.git
        final SslContext sslCtx;
        //是否启用SSL
        if (SSL) {
            sslCtx = SslContextBuilder.forClient()
                .trustManager(InsecureTrustManagerFactory.INSTANCE).build();
        } else {
            sslCtx = null;
        }

        // Configure the client.
        //配置服务端
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //启动类
            Bootstrap b = new Bootstrap();
            //设置group
            b.group(group)
            //设置channel ※NIO socket channel
             .channel(NioSocketChannel.class)
            //channel配置
            //ChannelOption.TCP_NODELAY , tcp no delay , 无延迟
             .option(ChannelOption.TCP_NODELAY, true)
            //配置消息处理器
             .handler(new ChannelInitializer<SocketChannel>() {
                 @Override
                 public void initChannel(SocketChannel ch) throws Exception {
                     //channel中的消息通道线(算是这么翻译吧)
                     ChannelPipeline p = ch.pipeline();
                     if (sslCtx != null) {
                         //配置了SSL,使用SSL处理器
                         //TODO 了解SSL
                         p.addLast(sslCtx.newHandler(ch.alloc(), HOST, PORT));
                     }
                     //添加日志处理器
                     //netty默认实现的日志处理器
                     //addLast,添加的消息通道的最末端(消息通过中没有处理器时,则处在第一位)
                     p.addLast(new LoggingHandler(LogLevel.INFO));
                     //添加客户端处理器
                     //顺序在日志处理器后面
                     p.addLast(new EchoClientHandler());
                 }
             });

            // Start the client.
            //b.connect(HOST, PORT) 打开与服务端的链接
            //sync() 等待链接的数据
            ChannelFuture f = b.connect(HOST, PORT).sync();

            // Wait until the connection is closed.
            // 在链接关闭前,一直处理于等待中
            f.channel().closeFuture().sync();
        } finally {
            // Shut down the event loop to terminate all threads.
            // 优雅的关闭 event loop,结束所有线程
            group.shutdownGracefully();
        }
    }
}
